﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using OWLServer.owl.tipos;

namespace OWLServerQL.dominio
{
    /// <summary>
    /// Elemento que representa un literal
    /// </summary>
    public class ElementoLiteral : Elemento
    {
        private string literal;

        /// <summary>
        /// Texto del elemento literal
        /// </summary>
        public string Literal
        {
            get { return literal; }
            set { literal = value; }
        }

        public ElementoLiteral()
            : base()
        {
        }

        public ElementoLiteral(string literal, bool negado)
            : base(negado)
        {
            this.Literal = literal;
        }

        public ElementoLiteral(string literal)
            : base()
        {
            this.Literal = literal;
        }

        override public String ToString()
        {
            StringBuilder bf = new StringBuilder();
            bf.Append("\nTipo Elemento: ");
            bf.Append(base.TipoElemento);
            bf.Append("\nNegado: ");
            bf.Append(base.Negado);
            bf.Append("\nLiteral: ");
            bf.Append(literal);
            bf.Append("\nUnion Anterior: ");
            bf.Append(base.UnionAnterior);
            bf.Append("\n++++++++++++>\n");
            if (base.ElementoSiguiente != null)
            {
                bf.Append(base.ElementoSiguiente.ToString());
            }
            return bf.ToString();
        }

        /// <summary>
        /// Comopone la lista de individuos que se están buscando en la consulta
        /// </summary>
        /// <param name="individuosOntologia">Lista de individuos de la Onlología seleccionada</param>
        /// <returns></returns>
        override public List<Individuo> owlServerQLToIndividuos(TipoElemento tipoElemento, List<Individuo> individuosOntologia)
        {
            List<Individuo> resultado = null;
            base.owlServerQLToIndividuos(tipoElemento, individuosOntologia);
            List<Individuo> conjuntoIzquierda = componerMisIndividuos(TipoElemento, individuosOntologia);
            List<Individuo> conjuntoDerecha = ElementoSiguiente == null ? null : ElementoSiguiente.owlServerQLToIndividuos(TipoElemento, individuosOntologia);
            resultado = unionIndividuos(conjuntoIzquierda, conjuntoDerecha);

            return resultado;
        }

        /// <summary>
        /// Compone los individuos que concidan con el elemento
        /// </summary>
        /// <param name="tipoElemento">Tipo de elemento</param>
        /// <param name="individuosOntologia">Individuos de la Ontologia</param>
        /// <returns>Lista de individuos de este elemento</returns>
        private List<Individuo> componerMisIndividuos(TipoElemento tipoElemento, List<Individuo> individuosOntologia)
        {
            List <Individuo> resultado = new List<Individuo> ();
            bool encontrado = false;
            int size;
            foreach (Individuo indi in individuosOntologia)
            {
                switch (tipoElemento)
                {
                    case dominio.TipoElemento.CLASS:
                        size = indi.Tipos.Count;
                        if (Literal == null && size > 0) // Si es null es porque es ALL, he insertamos todos los individuos que tengan un tipo
                        {
                            insertarIndividuo(resultado, indi);
                        }
                        else // Si no es ALL miramos si cumple la condicion
                        {
                            for (int i = 0; i < size && !encontrado; i++)
                            {
                                encontrado = componerResultado(resultado, indi, indi.Tipos[i]);
                            }
                        }
                        break;
                    case dominio.TipoElemento.SAME_AS:
                        size = indi.Iguales.Count;
                        if (Literal == null && size > 0) // Si es null es porque es ALL, he insertamos todos los individuos que tengan un igual
                        {
                            insertarIndividuo(resultado, indi);
                        }
                        else // Si no es ALL miramos si cumple la condicion
                        {
                            for (int i = 0; i < size && !encontrado; i++)
                            {
                                encontrado = componerResultado(resultado, indi, indi.Iguales[i]);
                            }
                        }
                        break;
                    case dominio.TipoElemento.DISTINCT:
                        size = indi.Diferentes.Count;
                        if (Literal == null && size > 0) // Si es null es porque es ALL, he insertamos todos los individuos que tengan un distinto
                        {
                            insertarIndividuo(resultado, indi);
                        }
                        else // Si no es ALL miramos si cumple la condicion
                        {
                            for (int i = 0; i < size && !encontrado; i++)
                            {
                                encontrado = componerResultado(resultado, indi, indi.Diferentes[i]);
                            }
                        }
                        break;
                    default:
                        break;
                }

                encontrado = false;
            }
            
            return resultado;
        }

        /// <summary>
        /// Compone el resultado de la busqueda de individuos
        /// </summary>
        /// <param name="resultado">Resultado que estamos componiendo</param>
        /// <param name="indi">Individuo que estamos analizando</param>
        /// <param name="elemento">Elemento que estamos comparado con el Literal</param>
        /// <returns>Indica si se ha encontrado un individuo que se ha insertado en el resultado</returns>
        private bool componerResultado(List<Individuo> resultado, Individuo indi, OWLServer.owl.tipos.Elemento elemento)
        {
            bool encontradoIndividuo = false;

            if (Negado && !elemento.Id.Equals(Literal))
            {
                insertarIndividuo(resultado, indi);
                encontradoIndividuo = true;
            }
            else
            {
                if (elemento.Id.Equals(Literal))
                {
                    insertarIndividuo(resultado, indi);
                    encontradoIndividuo = true;
                }
            }

            return encontradoIndividuo;
        }
    }
}
